package com.bwie.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bwie.es.EsProd;
import com.bwie.mapper.TbDictMapper;
import com.bwie.mapper.TbProdImageMapper;
import com.bwie.poi.ExcelUtil;
import com.bwie.pojo.TbDict;
import com.bwie.pojo.TbProd;
import com.bwie.pojo.TbProdImage;
import com.bwie.service.TbProdService;
import com.bwie.mapper.TbProdMapper;
import com.bwie.status.ProdEnum;
import com.bwie.utils.R;
import com.bwie.vo.PageInfoVo;
import com.bwie.vo.TbProdVo;
import io.jsonwebtoken.Jwts;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
* @author Lenovo
* @description 针对表【tb_prod(商品表)】的数据库操作Service实现
* @createDate 2025-03-25 18:37:54
*/
@Service
public class TbProdServiceImpl extends ServiceImpl<TbProdMapper, TbProd>
    implements TbProdService{

    @Autowired
    private TbProdMapper tbProdMapper;
    @Autowired
    private TbDictMapper tbDictMapper;
    @Autowired
    private TbProdImageMapper tbProdImageMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    ElasticsearchRestTemplate elasticsearchRestTemplate;
    @Autowired
    HttpServletRequest request;
    @Autowired
    HttpServletResponse response;

    @Override
    public R getProdList(PageInfoVo pageInfoVo) {
        //构造分页参数
        Page<TbProd> page = new Page<>(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());
        //获取分页数据
        LambdaQueryWrapper<TbProd> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByDesc(TbProd::getProdId);

        Page<TbProd> tbProdPage = tbProdMapper.selectPage(page,wrapper);

        //单独查图片
        for (TbProd record : tbProdPage.getRecords()) {
            List<TbProdImage> tbProdImages = tbProdImageMapper.selectList(
                    new LambdaQueryWrapper<TbProdImage>().eq(TbProdImage::getProdId, record.getProdId())
            );
            ArrayList<String> imageList = new ArrayList<>();
            for (TbProdImage tbProdImage : tbProdImages) {
                imageList.add(tbProdImage.getImageUrl());
            }
            record.setImageList(imageList);
        }

        return R.OK(tbProdPage);
    }

    @Override
    public R getDictList(Integer id) {

        //判断缓存是否存在
        String key = "dict_"+id;
        Boolean aBoolean = redisTemplate.hasKey(key);
        if(aBoolean){
            System.out.println("从缓存中获取");
            String s = redisTemplate.opsForValue().get(key);
            List<TbDict> tbDicts = JSON.parseArray(s, TbDict.class);
            return R.OK(tbDicts);
        }
        System.out.println("从数据库中获取");
        List<TbDict> tbDicts = tbDictMapper.selectList(
                new LambdaQueryWrapper<TbDict>()
                        .eq(TbDict::getDictType, id)
                        .orderByAsc(TbDict::getDictId)
        );
        redisTemplate.opsForValue().set(key,JSON.toJSONString(tbDicts));
        return R.OK(tbDicts);

//        //判断缓存中是否存在
//        String key = "dict_"+id;
//        Boolean hasKey = redisTemplate.hasKey(key);
//        if(hasKey){
//            System.out.println("从缓存中获取");
//            String s = redisTemplate.opsForValue().get(key);
//            List<TbDict> tbDicts = JSON.parseArray(s, TbDict.class);
//            return R.OK(tbDicts);
//        }
//        //从数据库中获取
//        System.out.println("从数据库中获取");
//        List<TbDict> tbDicts = tbDictMapper.selectList(
//                new LambdaQueryWrapper<TbDict>()
//                        .eq(TbDict::getDictType,id)
//                        .orderByAsc(TbDict::getDictValue)
//        );
//        redisTemplate.opsForValue().set(key,JSON.toJSONString(tbDicts));
//        return R.OK(tbDicts);
    }

    @Override
    public R getProdListFromEs(PageInfoVo pageInfoVo) {
        //构造 分页参数
        Integer pageNum = 0;
        if(pageInfoVo.getPageNum() > 0){
            pageNum = pageInfoVo.getPageNum() - 1;
        }
        PageRequest pageRequest = PageRequest.of(pageNum, pageInfoVo.getPageSize());

        //构造多条件查询
        BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
            //matchAll : 匹配所有的
        boolQueryBuilder.must(QueryBuilders.matchAllQuery());

        //关键字查询
        if(StringUtils.isNotBlank(pageInfoVo.getKeyWord())){
            boolQueryBuilder.must(QueryBuilders.matchQuery("prodName",pageInfoVo.getKeyWord()));
        }
        //价格区间
        if(pageInfoVo.getMinValue() != null){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("prodPrice").gte(pageInfoVo.getMinValue()));
        }
        if(pageInfoVo.getMaxValue() != null){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("prodPrice").lte(pageInfoVo.getMaxValue()));
        }
        //时间区间
        if(StringUtils.isNotEmpty(pageInfoVo.getBeginTime())){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime")
                    .format("yyyy-MM-dd HH:mm:ss")
                    .timeZone("GMT+8")
                    .gte(pageInfoVo.getBeginTime()));
        }
        if(StringUtils.isNotEmpty(pageInfoVo.getEndTime())){
            boolQueryBuilder.must(QueryBuilders.rangeQuery("createTime")
                    .format("yyyy-MM-dd HH:mm:ss")
                    .timeZone("GMT+8")
                    .lte(pageInfoVo.getEndTime()));
        }
        //仅获取待审核的商品
        boolQueryBuilder.must(QueryBuilders.termQuery("prodStatus",1));
        //高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("prodName").preTags("<font color='red'>").postTags("</font>");
        //排序
        FieldSortBuilder prodPriceOrder = SortBuilders.fieldSort("prodId").order(SortOrder.DESC);

        //开始查询
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        nativeSearchQueryBuilder.withQuery(boolQueryBuilder)
                .withPageable(pageRequest) //分页条件
                .withHighlightBuilder(highlightBuilder) //高亮
                .withSort(prodPriceOrder) //排序
        ;
        SearchHits<EsProd> searchHits = elasticsearchRestTemplate.search(nativeSearchQueryBuilder.build(), EsProd.class);
        
        //读取返回结果
        long total = searchHits.getTotalHits();
        ArrayList<EsProd> records = new ArrayList<>();
        for (SearchHit<EsProd> searchHit : searchHits.getSearchHits()) {
            EsProd esProd = searchHit.getContent();

            //获取高亮
            List<String> prodNameList = searchHit.getHighlightField("prodName");
            if(prodNameList != null && prodNameList.size() > 0){
                //替换成第一个记录
                esProd.setProdName(prodNameList.get(0));
            }

            records.add(esProd);
        }

        HashMap<String, Object> map = new HashMap<>();
        map.put("total",total);
        map.put("records",records);

        return R.OK(map);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R addProd(TbProd tbProd) {
        String token = request.getHeader("token");
        if(token == null){
            return R.ERROR(500,"请先登录");
        }

        //获取商家id
        Integer userId = Jwts.parser().setSigningKey("123456").parseClaimsJws(token).getBody().get("userId", Integer.class);

        //判断商品是否存在
        TbProd prod = tbProdMapper.selectOne(
                new LambdaQueryWrapper<TbProd>().eq(TbProd::getProdName, tbProd.getProdName())
        );
        if(prod != null){
            return R.ERROR(500,"商品已存在");
        }

        //保存商品
        tbProd.setProdStatus(ProdEnum.WAIT.getCode());
        tbProd.setCreateTime(new Date());
        tbProd.setUserId(userId);

        tbProdMapper.insert(tbProd);

        //添加商品的多个图片
        if(tbProd.getImageList() != null && tbProd.getImageList().size() > 0){
            for (String image : tbProd.getImageList()) {
                TbProdImage tbProdImage = new TbProdImage();
                tbProdImage.setProdId(tbProd.getProdId());
                tbProdImage.setImageUrl(image);

                tbProdImageMapper.insert(tbProdImage);
            }
        }

        return R.OK();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R updateProd(TbProd tbProd) {
        //判断商品是否存在
        TbProd prod = tbProdMapper.selectById(tbProd.getProdId());
        if(prod == null){
            return R.ERROR(404,"商品不存在");
        }
        //修改商品信息
        tbProdMapper.updateById(tbProd);

        //先删除商品原有图片
        tbProdImageMapper.delete(
                new LambdaQueryWrapper<TbProdImage>().eq(TbProdImage::getProdId,tbProd.getProdId())
        );
        //再添加新的商品图片
        if(tbProd.getImageList() != null && tbProd.getImageList().size() > 0){
            for (String image : tbProd.getImageList()) {
                TbProdImage tbProdImage = new TbProdImage();
                tbProdImage.setProdId(tbProd.getProdId());
                tbProdImage.setImageUrl(image);

                tbProdImageMapper.insert(tbProdImage);
            }
        }
        return R.OK();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R deleteProd(Integer prodId) {
        TbProd tbProd = tbProdMapper.selectById(prodId);
        if(tbProd == null){
            return R.ERROR(404,"商品不存在");
        }
        //删除商品
        tbProdMapper.deleteById(prodId);

        //查询图片列表
        List<TbProdImage> tbProdImages = tbProdImageMapper.selectList(
                new LambdaQueryWrapper<TbProdImage>().eq(TbProdImage::getProdId, prodId)
        );
        if(tbProdImages != null && tbProdImages.size() > 0){
            for (TbProdImage tbProdImage : tbProdImages) {
                tbProdImageMapper.deleteById(tbProdImage.getProdId());
            }
        }
        return R.OK();
    }

    @Override
    public R applyProdOnline(Integer prodId) {
        TbProd tbProd = tbProdMapper.selectById(prodId);
        if(tbProd == null){
            return R.ERROR(404,"商品不存在");
        }
        //申请上线 === 待审核
        tbProd.setProdStatus(ProdEnum.WAIT_CHECK.getCode());
        tbProdMapper.updateById(tbProd);

        //实时同步
        tbProd = tbProdMapper.selectById(prodId);
        EsProd esProd = BeanUtil.toBean(tbProd, EsProd.class);
        elasticsearchRestTemplate.save(esProd);

        return R.OK();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R sucProdStock(List<TbProdVo> prodVoList) {
        for (TbProdVo tbProdVo : prodVoList) {
            TbProd tbProd = tbProdMapper.selectById(tbProdVo.getProdId());
            if(tbProd.getProdStock() < tbProdVo.getBuyNum()){
//                return R.ERROR(500,"库存不足");
                throw new RuntimeException("库存不足");
            }
            tbProd.setProdStock(tbProd.getProdStock() - tbProdVo.getBuyNum());
            tbProdMapper.updateById(tbProd);
        }
        return R.OK();
    }

    @Override
    public void exportProdExcel() {
        //创建导出对象
        ExcelUtil<TbProd> tbProdExcelUtil = new ExcelUtil<>(TbProd.class);
        //查看数据
        List<TbProd> list = tbProdMapper.selectList(null);

        //导出文件
        tbProdExcelUtil.exportExcel(response,list,"商品列表");
    }

    @Override
    public void exportProdMore(String ids) {
        //把ids转化为数组
        String[] strings = ids.split(",");
        ArrayList<Integer> listId = new ArrayList<>();
        for (String id : strings) {
            listId.add(Integer.parseInt(id));
        }
        List<TbProd> list = tbProdMapper.selectBatchIds(listId);
        ExcelUtil<TbProd> tbProdExcelUtil = new ExcelUtil<>(TbProd.class);
        tbProdExcelUtil.exportExcel(response,list,"商品列表");
    }

    @Override
    public R importProdExcel(MultipartFile file) {
        try {
            //创建工具类对象
            ExcelUtil<TbProd> excelUtil = new ExcelUtil<>(TbProd.class);
            List<TbProd> tbProds = excelUtil.importExcel(file.getInputStream());
            String message = "成功导入" + tbProds.size() + "条数据";

            for (TbProd tbProd : tbProds) {
                if(tbProd.getProdId() == null){
                    //商品不存在，新增商品
                    tbProdMapper.insert(tbProd);
                    continue;
                }
                //保存到数据库
                TbProd prod = tbProdMapper.selectById(tbProd.getProdId());
                if(prod != null){
                    //商品存在，修改商品信息 === 覆盖商品
                    tbProdMapper.updateById(tbProd);
                }else{
                    //商品不存在，新增商品
                    tbProdMapper.insert(tbProd);
                }
            }
            return R.OK(message);
        } catch (IOException e) {
            e.printStackTrace();
            return R.ERROR(500,"导入失败");
        }
    }
}




